import base64
import pickle

from django.shortcuts import render

# Create your views here.
from django_redis import get_redis_connection
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework_jwt.views import ObtainJSONWebToken

from goods.models import SKU
from .serializers import CartSerializer, CartGetSerializer, CartDeleteSerializer, CartSelectAllView


class CartView(APIView):
    """
    购物车
    """

    def perform_authentication(self, request):
        """
        重写父类的用户验证方法，不在进入视图前就检查JWT
        """
        pass

    def post(self, request):
        """添加购物车"""
        ser = CartSerializer(data=request.data)
        ser.is_valid(raise_exception=True)
        sku_id = ser.validated_data.get("sku_id")
        count = ser.validated_data.get('count')
        selected = ser.validated_data.get('selected')

        # 判断用户是否登录
        try:
            user = request.user
        except:
            user = None

        if user is not None:
            # 用户已经登录保存到redis中
            conn = get_redis_connection("cart")
            # 写入sku_id和count hash
            conn.hincrby("cart_{}".format(user.id), sku_id, count)
            # 写入选中后状态　　set
            conn.sadd("cart_selected_{}".format(user.id), sku_id)

            return Response({"message": "ok"})

        else:
            # 用户未登录保存到cookie中
            # 获取cookie判断是否写入过
            cart = request.COOKIES.get("cart_cookie", None)

            # 对cookie进行解密
            if cart:
                cart = pickle.loads(base64.b64decode(cart))
            else:
                cart = {}

            # 判断cookie中是否已经有数据，有的话进行累加操作
            data = cart.get(sku_id, None)
            if data:
                # 累加操作
                count += int(data["count"])

            # 加密添加过的字典数据并返回
            cart[sku_id] = {
                "count": count,
                "selected": selected
            }
            cart_cookie = base64.b64encode(pickle.dumps(cart)).decode()
            # 构建响应体
            response = Response({"message": "ok"})
            response.set_cookie("cart_cookie", cart_cookie, max_age=60 * 60 * 24 * 7)

            return response

    def get(self, request):
        """购物车显示"""
        # 判断用户是否登录
        try:
            user = request.user
        except:
            user = None

        if user is not None:
            # 用户已经登录保存到redis中
            conn = get_redis_connection("cart")
            # 获取sku_id和count hash
            sku_count = conn.hgetall("cart_{}".format(user.id))
            # 获取选中后状态　　set
            sku_selected = conn.smembers("cart_selected_{}".format(user.id))

            # 统一数据格式，　将redis中的数据转化为字典嵌套
            cart = {}
            for sku_id, count in sku_count.items():
                cart[int(sku_id)] = {
                    "count": int(count),
                    "selected": sku_id in sku_selected,  # sku_id在sku_selected中的话返回True就是选中状态
                }

        else:
            # 用户未登录保存到cookie中
            # 获取cookie判断是否写入过
            cart = request.COOKIES.get("cart_cookie", None)

            # 对cookie进行解密
            if cart:
                cart = pickle.loads(base64.b64decode(cart))
            else:
                cart = {}
        # 数据查询
        skus = SKU.objects.filter(id__in=cart.keys())

        # 添加属性
        for sku in skus:
            sku.count = cart[sku.id]['count']
            sku.selected = cart[sku.id]['selected']

        # 序列化器返回
        ser = CartGetSerializer(skus, many=True)

        return Response(ser.data)

    def put(self, request):
        """更新购物车"""
        ser = CartSerializer(data=request.data)
        ser.is_valid(raise_exception=True)
        sku_id = ser.validated_data.get("sku_id")
        count = ser.validated_data.get('count')
        selected = ser.validated_data.get('selected')

        # 判断用户是否登录
        try:
            user = request.user
        except:
            user = None

        if user is not None:
            # 用户已经登录保存到redis中
            conn = get_redis_connection("cart")
            # 更新sku_id和count hash
            conn.hset("cart_{}".format(user.id), sku_id, count)
            # 更新选中后状态
            if selected:
                conn.sadd("cart_selected_{}".format(user.id), sku_id)
            else:
                conn.srem("cart_selected_{}".format(user.id), sku_id)

            return Response(ser.data)

        else:
            # 用户未登录保存到cookie中
            # 获取cookie判断是否写入过
            cart = request.COOKIES.get("cart_cookie", None)

            # 对cookie进行解密
            if cart:
                cart = pickle.loads(base64.b64decode(cart))
            else:
                cart = {}

            # 加密添加过的字典数据并返回
            cart["sku_id"] = {
                "count": count,
                "selected": selected
            }
            cart_cookie = base64.b64encode(pickle.dumps(cart)).decode()
            # 构建响应体
            response = Response(ser.data)
            response.set_cookie("cart_cookie", cart_cookie, max_age=60 * 60 * 24 * 7)

            return response

    def delete(self, request):
        ser = CartDeleteSerializer(data=request.data)
        ser.is_valid(raise_exception=True)
        sku_id = ser.validated_data["sku_id"]

        # 验证用户是否登录
        try:
            user = request.user
        except Exception:
            user = None

        # 如果用户登录从ｒｅｄｉｓ中删除
        if user is not None:
            conn = get_redis_connection("cart")
            conn.hdel("cart_{}".format(user.id), sku_id)
            conn.srem("cart_selected_{}".format(user.id), sku_id)
            return Response({"message": "ok"})

        # 没登录就从ｃｏｏｋｉｅ中删除数据
        else:
            # 获取cookie中的购物车信息
            cart = request.COOKIES.get("cart", None)
            # 　重构响应体
            response = Response({"message": "ok"})

            if cart is not None:
                # 对cookie进行解码
                cart = pickle.loads(base64.b64decode(cart))

                # 删除字典中的数据
                if sku_id in cart:
                    del cart[sku_id]

                # 加密更改后的字典数据
                cart_cookie = base64.b64encode(cart).decode()

                # 设置cookie
                response.set_cookie("cart_cookie", cart_cookie, max_age=60 * 60 * 24 * 7)

            return response


class SelectionView(APIView):
    def perform_authentication(self, request):
        """
        重写父类的用户验证方法，不在进入视图前就检查JWT
        """
        pass

    def put(self, request):
        """更新购物车"""
        ser = CartSelectAllView(data=request.data)
        ser.is_valid(raise_exception=True)
        selected = ser.validated_data["selected"]

        # 判断用户是否登录
        try:
            user = request.user
        except:
            user = None

        if user is not None:
            # 用户已经登录保存到redis中
            conn = get_redis_connection("cart")
            # 获取sku_id和count hash
            cart = conn.hgetall("cart_{}".format(user.id))
            sku_id_list = cart.keys()

            # 更新全选状态
            if selected:
                conn.sadd("cart_selected_{}".format(user.id), *sku_id_list)
            else:
                conn.srem("cart_selected_{}".format(user.id), *sku_id_list)

            return Response({"message": "ok"})

        else:
            # 用户未登录保存到cookie中
            # 获取cookie判断是否写入过
            cart = request.COOKIES.get("cart_cookie", None)

            # 对cookie进行解密
            if cart:
                cart = pickle.loads(base64.b64decode(cart))
            else:
                cart = {}

            for sku_id in cart:
                cart[sku_id]["selected"] = selected

            # 加密添加过的字典数据并返回
            cart_cookie = base64.b64decode(pickle.dumps(cart)).decode()

            # 构建响应体
            response = Response({"message": "ok"})
            response.set_cookie("cart_cookie", cart_cookie, max_age=60 * 60 * 24 * 7)

            return response
